/** Fichier qui implémente une classe représentant les matrices réelles 3x3
 * inversibles.
 *
 * Ce fichier contient l'implémentation de la classe MatriceGL3.
 *
 * @file MatriceGL3.cpp
 * @author Johan "Solo" Luisier
 *
 * @date 24 Juin 2011
 */
#include "MatriceGL3.hpp"

#include "Utils/Erreur.hpp"

#include <cmath>
#include <iostream>

using namespace std;

/** Constructeur permettant de créer une matrice scalaire.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * n'est pas nul. Une exception du type Erreur est lancée lorsque
 * l'objet n'est pas valide (matrice non inversible).
 *
 * @param[in] scalaire éléments diagonaux.
 */
MatriceGL3::MatriceGL3(const double& scalaire)
  : Matrice3x3( scalaire )
{
  verifie();
}

/** Constructeur standard.
 *
 * Constructeur permettant d'initialiser les trois colonnes de la
 * matrice à partir de 3 vecteurs. Dans ce cas la matrice peut être
 * vue comme un automorphisme de l'espace.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * n'est pas nul. Une exception du type Erreur est lancée lorsque
 * l'objet n'est pas valide (matrice non inversible).
 *
 * @param[in] x image de Ox.
 * @param[in] y image de Oy.
 * @param[in] z image de Oz.
 */
MatriceGL3::MatriceGL3(const Vecteur& x, const Vecteur& y, const Vecteur& z)
  : Matrice3x3( x, y, z )
{
  verifie();
}

/** Constructeur de copie, permet de dupliquer une instance de MatriceGL3.
 *
 * Ici pas besoin de vérifier si la matrice à copier a bien un
 * déterminant non nul : c'est déjà une MatriceGL3.
 *
 * @param[in] mat objet à copier.
 */
MatriceGL3::MatriceGL3(const MatriceGL3& mat)
  : Matrice3x3( mat )
{}

/** Constructeur permettant de promouvoir une Matrice3x3 en MatriceGL3.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * n'est pas nul. Une exception du type Erreur est lancée lorsque
 * l'objet n'est pas valide (matrice non inversible).
 *
 * @param[in] mat objet à promouvoir.
 */
MatriceGL3::MatriceGL3(const Matrice3x3& mat)
  : Matrice3x3( mat )
{
  verifie();
}

/** Constructeur permettant de construire une MatriceGL3 à partir de
 * ses trois éléments diagonaux.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * n'est pas nul. Une exception du type Erreur est lancée lorsque
 * l'objet n'est pas valide (matrice non inversible).
 *
 * @param[in] m11 élément (1,1) de la matrice.
 * @param[in] m22 élément (2,2) de la matrice.
 * @param[in] m33 élément (3,3) de la matrice.
 */
MatriceGL3::MatriceGL3(const double& m11, const double& m22, const double& m33)
  : Matrice3x3( m11, m22, m33 )
{
  verifie();
}

/** Destructeur, virtuel pour assurer une bonne séquence d'appel.
 *
 * Le destructeur n'a rien de spécial à faire.
 */
MatriceGL3::~MatriceGL3()
{}

/** Opérateur d'affectation
 *
 * Redéfinition de Matrice3x3::operator=, qui permet de vérifier que
 * la matrice est bien inversible.
 *
 * On vérifie que le déterminant n'est pas nul. Une exception du type
 * Erreur est lancée lorsque l'objet n'est pas valide (matrice non
 * inversible).
 *
 * @param[in] mat objet à copier.
 *
 * @return référence sur l'instance courante modifiée.
 */
MatriceGL3& MatriceGL3::operator=(const Matrice3x3& mat)
{
  this -> Matrice3x3::operator=( mat );
  
  verifie();

  return *this;
}

/** Opérateur d'inversion d'une matrice.
 *
 * Permet d'obtenir l'inverse d'une matrice.
 * 
 * @return une nouvelle instance, qui est l'inverse de l'instance courante.
 */
MatriceGL3 MatriceGL3::inverse() const
{
  double det( determinant() );

  if ( abs( det - 1. ) < 1e-7 )
    return comatrice().transpose();
  else if ( abs( det + 1. ) < 1e-7 )
    return - comatrice().transpose();
  else
    return comatrice().transpose() * ( 1. / det );
}

/** Méthode qui vérifie que la matrice fait bien partie du groupe @f$ GL \left(
* 3 \right) @f$.
 *
 * La méthode vérifie que le déterminant n'est pas nul. Lorsque
 * celui-ci est nul, une exception du type Erreur est lancée.
 *
 * @throw Erreur si le déterminant est nul.
 */
void MatriceGL3::verifie() const
{
  if ( abs( determinant() ) < 1.e-7 )
    {
      cerr << "Déterminant nul" << endl;
      throw Erreur( false, 0, "Déterminant nul", "MatriceGL3" );
    }
}
